﻿using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System.Collections.Generic;
using System.Linq;
using OpenCvSharp.WpfExtensions;
using System.Windows.Controls;
using OpenCvSharp.Features2D;

namespace ImageMatchTool
{
    public partial class MainWindow : System.Windows.Window
    {
        private Mat templateImage;
        private Mat sourceImage;
        private Mat resultImage;

        public MainWindow()
        {
            InitializeComponent();
            InitializeUI();
        }

        private void InitializeUI()
        {
            sliderThreshold.ValueChanged += (s, e) =>
            {
                lblThresholdValue.Content = sliderThreshold.Value.ToString("F1");
            };
        }

        private void LoadTemplate_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Title = "选择模板图像",
                Filter = "图像文件|*.jpg;*.jpeg;*.png;*.bmp;*.tiff|所有文件|*.*"
            };

            if (openFileDialog.ShowDialog() == true)
            {
                try
                {
                    templateImage = Cv2.ImRead(openFileDialog.FileName);
                    if (templateImage.Empty())
                    {
                        MessageBox.Show("无法加载模板图像！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }

                    imgTemplate.Source = templateImage.ToBitmapSource();
                    statusText.Text = $"模板图像已加载: {Path.GetFileName(openFileDialog.FileName)}";

                    tempGroupBox.Header = $"模板图像(Template Image)--({templateImage.Width}x{templateImage.Height})";

                    CheckCanMatch();
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"加载模板图像时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private void LoadSource_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Title = "选择原图像",
                Filter = "图像文件|*.jpg;*.jpeg;*.png;*.bmp;*.tiff|所有文件|*.*"
            };

            if (openFileDialog.ShowDialog() == true)
            {
                try
                {
                    sourceImage = Cv2.ImRead(openFileDialog.FileName);
                    if (sourceImage.Empty())
                    {
                        MessageBox.Show("无法加载原图像！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }

                    imgSource.Source = sourceImage.ToBitmapSource();
                    
                    // 添加以下代码以确保图像正确显示
                    imgSource.Width = sourceImage.Width;
                    imgSource.Height = sourceImage.Height;
                    
                    // 更新 Canvas 大小以适应图像
                    canvasSource.Width = sourceImage.Width;
                    canvasSource.Height = sourceImage.Height;

                    statusText.Text = $"原图像已加载: {Path.GetFileName(openFileDialog.FileName)}";
                    CheckCanMatch();

                    sourceGroupBox.Header = $"原图像 (Source Image)--({sourceImage.Width}x{sourceImage.Height})";

                    // 启用截取按钮
                    btnCropTemplate.IsEnabled = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"加载原图像时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private void CheckCanMatch()
        {
            btnMatch.IsEnabled = templateImage != null && !templateImage.Empty() &&
                                sourceImage != null && !sourceImage.Empty();
        }

        private async void StartMatch_Click(object sender, RoutedEventArgs e)
        {
            if (templateImage == null || sourceImage == null)
                return;

            btnMatch.IsEnabled = false;
            progressBar.Visibility = Visibility.Visible;
            progressBar.IsIndeterminate = true;
            statusText.Text = "正在进行图像匹配...";

            try
            {
                var selectedMethod = ((ComboBoxItem)cmbMatchMethod.SelectedItem).Tag.ToString();
                var threshold = sliderThreshold.Value;

                await Task.Run(() => PerformMatching(selectedMethod, threshold));

                if (resultImage != null && !resultImage.Empty())
                {
                    imgResult.Source = resultImage.ToBitmapSource();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"匹配过程中出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                btnMatch.IsEnabled = true;
                progressBar.Visibility = Visibility.Collapsed;
                statusText.Text = "匹配完成";
            }
        }

        private void PerformMatching(string method, double threshold)
        {
            switch (method)
            {
                case "Template":
                    PerformTemplateMatching(threshold);
                    break;
                case "Shape":
                    PerformShapeMatching(threshold);
                    break;
                case "Feature":
                    PerformFeatureMatching(threshold);
                    break;
            }
        }

        private void PerformTemplateMatching(double threshold)
        {
            try
            {
                // 模板匹配
                var result = new Mat();
                Cv2.MatchTemplate(sourceImage, templateImage, result, TemplateMatchModes.CCoeffNormed);

                // 查找最佳匹配位置
                Cv2.MinMaxLoc(result, out _, out double maxVal, out _, out OpenCvSharp.Point maxLoc);

                // 创建结果图像
                resultImage = sourceImage.Clone();

                if (maxVal >= threshold)
                {
                    // 绘制匹配区域
                    var rect = new OpenCvSharp.Rect(maxLoc.X, maxLoc.Y, templateImage.Width, templateImage.Height);
                    Cv2.Rectangle(resultImage, rect, Scalar.Red, 3);

                    // 在矩形上方添加匹配度文本
                    var text = $"Match: {maxVal:F3}";
                    var textSize = Cv2.GetTextSize(text, HersheyFonts.HersheySimplex, 0.7, 2, out _);
                    var textPos = new OpenCvSharp.Point(maxLoc.X, Math.Max(maxLoc.Y - 10, textSize.Height + 10));

                    Cv2.Rectangle(resultImage,
                        new OpenCvSharp.Point(textPos.X - 5, textPos.Y - textSize.Height - 5),
                        new OpenCvSharp.Point(textPos.X + textSize.Width + 5, textPos.Y + 5),
                        Scalar.Red, -1);

                    Cv2.PutText(resultImage, text, textPos, HersheyFonts.HersheySimplex, 0.7, Scalar.White, 2);

                    Dispatcher.Invoke(() =>
                    {
                        txtMatchInfo.Text = $"模板匹配结果:\n" +
                                          $"最佳匹配度: {maxVal:F4}\n" +
                                          $"匹配位置: ({maxLoc.X}, {maxLoc.Y})\n" +
                                          $"匹配阈值: {threshold:F1}\n" +
                                          $"匹配状态: {(maxVal >= threshold ? "成功" : "失败")}\n" +
                                          $"模板尺寸: {templateImage.Width} x {templateImage.Height}\n" +
                                          $"源图尺寸: {sourceImage.Width} x {sourceImage.Height}";
                    });
                }
                else
                {
                    Dispatcher.Invoke(() =>
                    {
                        txtMatchInfo.Text = $"模板匹配结果:\n" +
                                          $"最佳匹配度: {maxVal:F4}\n" +
                                          $"匹配阈值: {threshold:F1}\n" +
                                          $"匹配状态: 未找到满足阈值的匹配\n" +
                                          $"建议: 降低匹配阈值或更换模板图像";
                    });
                }
            }
            catch (Exception ex)
            {
                Dispatcher.Invoke(() =>
                {
                    txtMatchInfo.Text = $"模板匹配失败:\n{ex.Message}";
                });
            }
        }

        private void PerformShapeMatching(double threshold)
        {
            try
            {
                // 转换为灰度图
                var templateGray = new Mat();
                var sourceGray = new Mat();
                Cv2.CvtColor(templateImage, templateGray, ColorConversionCodes.BGR2GRAY);
                Cv2.CvtColor(sourceImage, sourceGray, ColorConversionCodes.BGR2GRAY);

                // 边缘检测
                var templateEdges = new Mat();
                var sourceEdges = new Mat();
                Cv2.Canny(templateGray, templateEdges, 50, 150);
                Cv2.Canny(sourceGray, sourceEdges, 50, 150);

                // 查找轮廓
                OpenCvSharp.Point[][] templateContours;
                OpenCvSharp.Point[][] sourceContours;
                HierarchyIndex[] templateHierarchy;
                HierarchyIndex[] sourceHierarchy;
                Cv2.FindContours(templateEdges, out templateContours, out templateHierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
                Cv2.FindContours(sourceEdges, out sourceContours, out sourceHierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);

                resultImage = sourceImage.Clone();

                if (templateContours.Length > 0 && sourceContours.Length > 0)
                {
                    // 选择最大的轮廓作为主要形状
                    var templateMainContour = templateContours.OrderByDescending(c => Cv2.ContourArea(c)).First();

                    double bestMatch = 0;
                    int bestContourIndex = -1;

                    // 与每个源轮廓进行形状匹配
                    for (int i = 0; i < sourceContours.Length; i++)
                    {
                        if (Cv2.ContourArea(sourceContours[i]) < 100) // 忽略太小的轮廓
                            continue;

                        try
                        {
                            double match = Cv2.MatchShapes(templateMainContour, sourceContours[i], ShapeMatchModes.I1, 0);

                            // 形状匹配返回的是距离，越小越相似，需要转换为相似度
                            double similarity = 1.0 / (1.0 + match);

                            if (similarity > bestMatch)
                            {
                                bestMatch = similarity;
                                bestContourIndex = i;
                            }
                        }
                        catch
                        {
                            // 某些轮廓可能无法计算形状匹配，跳过
                            continue;
                        }
                    }

                    if (bestContourIndex >= 0 && bestMatch >= threshold)
                    {
                        // 绘制最佳匹配的轮廓
                        Cv2.DrawContours(resultImage, sourceContours, bestContourIndex, Scalar.Red, 3);

                        // 计算轮廓的边界框并添加文本
                        var boundingRect = Cv2.BoundingRect(sourceContours[bestContourIndex]);
                        var text = $"Shape: {bestMatch:F3}";
                        var textPos = new OpenCvSharp.Point(boundingRect.X, boundingRect.Y - 10);
                        Cv2.PutText(resultImage, text, textPos, HersheyFonts.HersheySimplex, 0.7, Scalar.Red, 2);
                    }

                    Dispatcher.Invoke(() =>
                    {
                        txtMatchInfo.Text = $"形状匹配结果:\n" +
                                          $"最佳相似度: {bestMatch:F4}\n" +
                                          $"匹配阈值: {threshold:F1}\n" +
                                          $"匹配状态: {(bestMatch >= threshold ? "成功" : "失败")}\n" +
                                          $"模板轮廓数: {templateContours.Length}\n" +
                                          $"源图轮廓数: {sourceContours.Length}\n" +
                                          $"主要轮廓面积: {(templateContours.Length > 0 ? Cv2.ContourArea(templateMainContour) : 0):F0}";
                    });
                }
                else
                {
                    Dispatcher.Invoke(() =>
                    {
                        txtMatchInfo.Text = "形状匹配失败:\n未找到足够的轮廓进行匹配\n建议: 调整图像对比度或使用其他匹配方法";
                    });
                }
            }
            catch (Exception ex)
            {
                Dispatcher.Invoke(() =>
                {
                    txtMatchInfo.Text = $"形状匹配失败:\n{ex.Message}";
                });
            }
        }

        private void PerformFeatureMatching(double threshold)
        {
            try
            {
                // 转換為灰度圖
                var templateGray = new Mat();
                var sourceGray = new Mat();
                Cv2.CvtColor(templateImage, templateGray, ColorConversionCodes.BGR2GRAY);
                Cv2.CvtColor(sourceImage, sourceGray, ColorConversionCodes.BGR2GRAY);

                // 创建SIFT检测器
                var sift = SIFT.Create();

                // 检测关键点和描述符
                KeyPoint[] templateKeypoints;
                KeyPoint[] sourceKeypoints;
                var templateDescriptors = new Mat();
                var sourceDescriptors = new Mat();

                sift.DetectAndCompute(templateGray, null, out templateKeypoints, templateDescriptors);
                sift.DetectAndCompute(sourceGray, null, out sourceKeypoints, sourceDescriptors);

                resultImage = sourceImage.Clone();

                if (templateKeypoints.Length > 0 && sourceKeypoints.Length > 0)
                {
                    // 创建匹配器
                    var matcher = new BFMatcher();
                    var matches = matcher.Match(templateDescriptors, sourceDescriptors);

                    // 根据距离排序
                    var goodMatches = matches.Where(m => m.Distance < 0.7f * matches.Max(x => x.Distance)).ToArray();

                    double matchRatio = (double)goodMatches.Length / Math.Min(templateKeypoints.Length, sourceKeypoints.Length);

                    if (matchRatio >= threshold && goodMatches.Length >= 4)
                    {
                        // 绘制匹配点
                        var matchImage = new Mat();
                        Cv2.DrawMatches(templateImage, templateKeypoints, sourceImage, sourceKeypoints,
                                      goodMatches, matchImage);

                        // 简化版本：只绘制匹配的关键点，不进行单应性变换
                        foreach (var match in goodMatches.Take(20)) // 只显示前20个最好的匹配
                        {
                            var pt = sourceKeypoints[match.TrainIdx].Pt;
                            Cv2.Circle(resultImage, new OpenCvSharp.Point((int)pt.X, (int)pt.Y), 5, Scalar.Red, 2);
                        }

                        resultImage = matchImage;
                    }

                    Dispatcher.Invoke(() =>
                    {
                        txtMatchInfo.Text = $"特征匹配结果:\n" +
                                          $"模板关键点: {templateKeypoints.Length}\n" +
                                          $"源图关键点: {sourceKeypoints.Length}\n" +
                                          $"总匹配数: {matches.Length}\n" +
                                          $"好匹配数: {goodMatches.Length}\n" +
                                          $"匹配比率: {matchRatio:F4}\n" +
                                          $"匹配阈值: {threshold:F1}\n" +
                                          $"匹配状态: {(matchRatio >= threshold ? "成功" : "失败")}";
                    });
                }
                else
                {
                    Dispatcher.Invoke(() =>
                    {
                        txtMatchInfo.Text = "特征匹配失败:\n未检测到足够的关键点\n建议: 使用纹理更丰富的图像或调整参数";
                    });
                }
            }
            catch (Exception ex)
            {
                Dispatcher.Invoke(() =>
                {
                    txtMatchInfo.Text = $"特征匹配失败:\n{ex.Message}";
                });
            }
        }

        private System.Windows.Point? cropStartPoint;
        private System.Windows.Shapes.Rectangle? selectionRect;
        private bool isCropping = false;

        private void CropTemplate_Click(object sender, RoutedEventArgs e)
        {
            if (!isCropping)
            {
                // 开始截取模式
                isCropping = true;
                btnCropTemplate.Content = "取消截取";
                statusText.Text = "请在原图像上拖动鼠标选择模板区域";
                
                canvasSource.MouseLeftButtonDown += Cropping_MouseLeftButtonDown;
                canvasSource.MouseMove += Cropping_MouseMove;
                canvasSource.MouseLeftButtonUp += Cropping_MouseLeftButtonUp;
            }
            else
            {
                // 取消截取模式
                CancelCropping();
            }
        }

        private void CancelCropping()
        {
            isCropping = false;
            btnCropTemplate.Content = "截取模板";
            statusText.Text = "就绪";

            if (selectionRect != null)
            {
                canvasSource.Children.Remove(selectionRect);
                selectionRect = null;
            }

            canvasSource.MouseLeftButtonDown -= Cropping_MouseLeftButtonDown;
            canvasSource.MouseMove -= Cropping_MouseMove;
            canvasSource.MouseLeftButtonUp -= Cropping_MouseLeftButtonUp;
        }

        private void Cropping_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (isCropping)
            {
                cropStartPoint = e.GetPosition(canvasSource);

                selectionRect = new System.Windows.Shapes.Rectangle
                {
                    Stroke = Brushes.Red,
                    StrokeThickness = 2,
                    Fill = new SolidColorBrush(Color.FromArgb(50, 255, 0, 0))
                };

                Canvas.SetLeft(selectionRect, cropStartPoint.Value.X);
                Canvas.SetTop(selectionRect, cropStartPoint.Value.Y);

                canvasSource.Children.Add(selectionRect);
            }
        }

        private void Cropping_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (isCropping && cropStartPoint.HasValue && selectionRect != null)
            {
                var currentPoint = e.GetPosition(canvasSource);

                var x = Math.Min(cropStartPoint.Value.X, currentPoint.X);
                var y = Math.Min(cropStartPoint.Value.Y, currentPoint.Y);
                var width = Math.Abs(currentPoint.X - cropStartPoint.Value.X);
                var height = Math.Abs(currentPoint.Y - cropStartPoint.Value.Y);

                Canvas.SetLeft(selectionRect, x);
                Canvas.SetTop(selectionRect, y);
                selectionRect.Width = width;
                selectionRect.Height = height;
            }
        }

        private void Cropping_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (isCropping && selectionRect != null && sourceImage != null)
            {
                var currentPoint = e.GetPosition(canvasSource);

                // 计算实际图像上的坐标
                var img = imgSource;
                var imgWidth = img.ActualWidth;
                var imgHeight = img.ActualHeight;
                var scaleX = sourceImage.Width / imgWidth;
                var scaleY = sourceImage.Height / imgHeight;

                var x = (int)(Math.Min(cropStartPoint.Value.X, currentPoint.X) * scaleX);
                var y = (int)(Math.Min(cropStartPoint.Value.Y, currentPoint.Y) * scaleY);
                var width = (int)(Math.Abs(currentPoint.X - cropStartPoint.Value.X) * scaleX);
                var height = (int)(Math.Abs(currentPoint.Y - cropStartPoint.Value.Y) * scaleY);

                if (width > 0 && height > 0 && x >= 0 && y >= 0 && x + width <= sourceImage.Width && y + height <= sourceImage.Height)
                {
                    var rect = new OpenCvSharp.Rect(x, y, width, height);
                    var croppedImage = new Mat(sourceImage, rect);

                    var result = MessageBox.Show(
                        "是否要将截取的区域设置为新的模板图像？",
                        "确认替换模板",
                        MessageBoxButton.YesNo,
                        MessageBoxImage.Question
                    );

                    if (result == MessageBoxResult.Yes)
                    {
                        templateImage?.Dispose();
                        templateImage = croppedImage;
                        imgTemplate.Source = templateImage.ToBitmapSource();
                        tempGroupBox.Header = $"模板图像(Template Image)--({templateImage.Width}x{templateImage.Height})";
                        statusText.Text = "已更新模板图像";
                        CheckCanMatch();
                    }
                    else
                    {
                        croppedImage.Dispose();
                    }
                }

                CancelCropping();
            }
        }

        protected override void OnClosed(EventArgs e)
        {
            // 清理OpenCV资源
            templateImage?.Dispose();
            sourceImage?.Dispose();
            resultImage?.Dispose();
            base.OnClosed(e);
        }
    }
}